package com.exam.api.modules.dict.service.impl;

import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.exam.api.common.exception.GlobalException;
import com.exam.api.common.utils.BeanHelper;
import com.exam.api.modules.dict.domain.SysDict;
import com.exam.api.modules.dict.domain.SysDictItem;
import com.exam.api.modules.dict.dto.DictOptionDTO;
import com.exam.api.modules.dict.dto.SysDictItemDTO;
import com.exam.api.modules.dict.dto.SysDictItemSearchDTO;
import com.exam.api.modules.dict.mapper.SysDictItemMapper;
import com.exam.api.modules.dict.service.SysDictItemService;
import com.exam.api.modules.dict.service.SysDictService;
import com.exam.api.modules.dict.vo.SysDictItemVO;
import jakarta.annotation.PostConstruct;
import jakarta.annotation.Resource;
import org.redisson.api.RList;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.concurrent.TimeUnit;

/**
 * @author iaa
 * @description 针对表【sys_dict_item】的数据库操作Service实现
 * @createDate 2025-06-17 14:00:39
 */
@Service
public class SysDictItemServiceImpl extends ServiceImpl<SysDictItemMapper, SysDictItem> implements SysDictItemService {

    @Resource
    private SysDictService sysDictService;
    @Resource
    private RedissonClient redissonClient;
    @Resource
    private ThreadPoolTaskExecutor appExecutor;


    @PostConstruct
    @Scheduled(fixedRate = 30, timeUnit = TimeUnit.MINUTES)
    public void updateDict() {
        appExecutor.execute(() -> {
            try {
                List<SysDict> list = sysDictService.list();
                list.forEach(dict -> {
                    refreshCache(null, dict);
                });
            } catch (Exception e) {
                log.error("<<<=== 更新字典缓存失败", e);
            }
        });
    }

    /**
     * 获取字典项列表
     *
     * @param dictCode 字典
     * @return 字典项列表
     */
    @Override
    public RList<SysDictItem> getDictRList(String dictCode) {
        return redissonClient.getList("Dict:" + dictCode);
    }

    /**
     * 刷新缓存
     *
     * @param dictItem 字典项
     * @param rawDict  字典
     */
    private void refreshCache(SysDictItem dictItem, SysDict rawDict) {
        SysDict dict = Optional.ofNullable(rawDict)
                .orElseGet(() -> sysDictService.getById(dictItem.getDictId()));
        RLock lock = redissonClient.getLock("RefreshDictCacheLock:" + dict.getCode());
        try {
            if (lock.tryLock(2, 5, TimeUnit.MINUTES)) {
                RList<SysDictItem> dictRList = getDictRList(dict.getCode());
                dictRList.clear();
                List<SysDictItem> dictItems = lambdaQuery()
                        .eq(SysDictItem::getDictId, dict.getId())
                        .list();
                dictRList.addAll(dictItems);
            }
        } catch (InterruptedException e) {
            throw new GlobalException("刷新缓存失败");
        }finally {
            if (lock.isHeldByCurrentThread()) {
                lock.unlock();
            }
        }
    }


    @Override
    public boolean save(SysDictItem entity) {
        boolean saved = super.save(entity);
        refreshCache(entity, null);
        return saved;
    }

    @Override
    public boolean updateById(SysDictItem entity) {
        boolean updatedById = super.updateById(entity);
        refreshCache(entity, null);
        return updatedById;
    }

    @Override
    public void createSysDictItem(SysDictItemDTO dto) {
        save(dto.converter());
    }

    @Override
    public void updateSysDictItem(SysDictItemDTO dto) {
        SysDictItem converter = dto.converter();
        updateById(converter);
    }

    @Override
    public IPage<SysDictItemVO> pageSysDictItem(SysDictItemSearchDTO dto) {
        QueryWrapper<SysDictItem> query = new QueryWrapper<>();
        query.lambda().eq(ObjectUtil.isNotNull(dto.getDictId()), SysDictItem::getDictId, dto.getDictId());
        query.lambda().eq(SysDictItem::getIsDelete, 0);
        query.lambda().orderByDesc(SysDictItem::getCreateTime);
        return baseMapper.selectPageBy(dto.buildPage(), query);
    }

    @Override
    public void delSysDictItem(Long dictItemId) {
        SysDictItem dictItem = getById(dictItemId);
        removeById(dictItemId);
        refreshCache(dictItem, null);
    }

    @Override
    public SysDictItemVO selectById(Long id) {
        SysDictItem byId = getById(id);
        return BeanHelper.copyProperties(byId, SysDictItemVO.class);
    }

    @Override
    public List<DictOptionDTO> getDictItemByDictCode(String code) {
        RList<SysDictItem> dictRList = getDictRList(code);
        List<DictOptionDTO> list = dictRList.stream().map(dictItem -> {
            DictOptionDTO option = new DictOptionDTO();
            option.setLabel(dictItem.getDictText());
            option.setValue(dictItem.getDictValue());
            return option;
        }).toList();
        return list;
    }

    @Override
    public Map<String, List<DictOptionDTO>> getDictItemByCodeList(List<String> codeList) {
        Map<String, List<DictOptionDTO>> list = new HashMap<>();
        Set<String> codes = new HashSet<>(codeList);
        for (String code : codes) {
            List<DictOptionDTO> dictItems = getDictItemByDictCode(code);
            list.put(code, dictItems);
        }
        return list;
    }
}




